package com.yunwaikeji.gy_tool_library.adapter.recycler;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.yunwaikeji.gy_tool_library.info.GYRecyclerInfo;
import com.yunwaikeji.gy_tool_library.view.GYLinearLayout;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;

public abstract class GYRecyclerAdapter<Model, VH extends GYViewHolder> extends RecyclerView.Adapter<VH> implements GYRecyclerInfo {
    private final Integer mLayoutId;
    private List<Model> mModelList;
    private GYLinearLayout mHeaderLayout;
    private GYLinearLayout mFooterLayout;
    private final LinkedHashSet<Integer> childClickViewIds;

    public GYRecyclerAdapter() {
        this(null, null);
    }

    public GYRecyclerAdapter(Integer layoutId) {
        this(layoutId, null);
    }

    public GYRecyclerAdapter(List<Model> modelList) {
        this(null, modelList);
    }

    public GYRecyclerAdapter(Integer layoutId, List<Model> modelList) {
        mLayoutId = layoutId;
        mModelList = modelList;
        if (mModelList == null) {
            mModelList = new ArrayList<>();
        }
        childClickViewIds = new LinkedHashSet<>();
    }

    @NonNull
    @Override
    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        GYViewHolder viewHolder;
        if (viewType == ItemViewType.HEADER) {
            viewHolder = new GYViewHolder(mHeaderLayout);
        } else if (viewType == ItemViewType.FOOTER) {
            viewHolder = new GYViewHolder(mFooterLayout);
        } else {
            View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);
            viewHolder = new GYViewHolder(view);
        }
        viewHolder.setRecyclerAdapter(this);
        return (VH) viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull VH holder, int position) {
        int position1 = position - getHeaderLayoutCount();
        if (mOnItemClickListener != null) {
            holder.itemView.setOnClickListener(v ->
                    mOnItemClickListener.onItemClick(this, holder.itemView, position1)
            );
        }
        if (mOnItemLongClickListener != null) {
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    return mOnItemLongClickListener.onItemLongClick(GYRecyclerAdapter.this, holder.itemView, position1);
                }
            });
        }
        if (mOnItemChildClickListener != null) {
            for (int viewId : getChildClickViewIds()) {
                View view = holder.getView(viewId);
                if (!view.isClickable()) {
                    view.setClickable(true);
                }
                view.setOnClickListener(view1 ->
                        mOnItemChildClickListener.onItemChildClick(this, view1, position1)
                );
            }
        }
        if (position1 < mModelList.size()) {
            convert(holder, mModelList.get(position1));
        }
    }

    @Override
    public int getItemCount() {
        return getHeaderLayoutCount() + mModelList.size() + getFooterLayoutCount();
    }

    protected abstract void convert(VH holder, Model model);

    public GYRecyclerAdapter<Model, VH> addData(List<Model> modelList) {
        if (mModelList == null) {
            mModelList = new ArrayList<>();
        }
        mModelList.addAll(modelList);
        notifyItemRangeInserted(getHeaderLayoutCount() + mModelList.size(), modelList.size());
        return this;
    }

    public GYRecyclerAdapter<Model, VH> addData(Model... models) {
        return addData(Arrays.asList(models));
    }

    public GYRecyclerAdapter<Model, VH> setData(List<Model> modelList) {
        mModelList = modelList;
        notifyDataSetChanged();
        return this;
    }

    public GYRecyclerAdapter<Model, VH> setData(Model... models) {
        return setData(Arrays.asList(models));
    }

    public List<Model> getData() {
        return mModelList;
    }

    public GYRecyclerAdapter<Model, VH> addHeaderView(View view, int index, int orientation) {
        if (mHeaderLayout == null) {
            mHeaderLayout = new GYLinearLayout(view.getContext());
            switch (orientation) {
                case LinearLayout.VERTICAL:
                    mHeaderLayout.getViewSet().setSizePx(MATCH_PARENT, WRAP_CONTENT).setOrientation(LinearLayout.VERTICAL);
                    break;
                case LinearLayout.HORIZONTAL:
                    mHeaderLayout.getViewSet().setSizePx(WRAP_CONTENT, MATCH_PARENT).setOrientation(LinearLayout.HORIZONTAL);
                    break;
            }
        }
        final int childCount = mHeaderLayout.getChildCount();
        if (index < 0 || index > childCount) {
            index = childCount;
        }
        mHeaderLayout.getViewSet().addViews(index, view);
        return this;
    }

    public GYRecyclerAdapter<Model, VH> addHeaderView(View header, int index) {
        return addHeaderView(header, index, mHeaderLayout == null ? LinearLayout.VERTICAL : mHeaderLayout.getOrientation());
    }

    public GYRecyclerAdapter<Model, VH> addHeaderView(View header) {
        return addHeaderView(header, -1);
    }

    public GYRecyclerAdapter<Model, VH> removeHeaderView(View header) {
        if (!hasHeaderLayout()) {
            return this;
        }
        mHeaderLayout.removeView(header);
        if (mHeaderLayout.getChildCount() == 0) {
            notifyItemRangeRemoved(0, mModelList.size() + getFooterLayoutCount());
        }
        return this;
    }

    public GYRecyclerAdapter<Model, VH> removeHeaderAllViews() {
        if (!hasHeaderLayout()) {
            return this;
        }
        mHeaderLayout.removeAllViews();
        notifyItemRangeRemoved(0, mModelList.size() + getFooterLayoutCount());
        return this;
    }

    private boolean hasHeaderLayout() {
        return mHeaderLayout != null && mHeaderLayout.getChildCount() > 0;
    }

    public int getHeaderLayoutCount() {
        return hasHeaderLayout() ? 1 : 0;
    }

    public GYRecyclerAdapter<Model, VH> addFooterView(View view, int index, int orientation) {
        if (mFooterLayout == null) {
            mFooterLayout = new GYLinearLayout(view.getContext());
            switch (orientation) {
                case LinearLayout.VERTICAL:
                    mFooterLayout.getViewSet().setSizePx(MATCH_PARENT, WRAP_CONTENT).setOrientation(LinearLayout.VERTICAL);
                    break;
                case LinearLayout.HORIZONTAL:
                    mFooterLayout.getViewSet().setSizePx(WRAP_CONTENT, MATCH_PARENT).setOrientation(LinearLayout.HORIZONTAL);
                    break;
            }
        }
        final int childCount = mFooterLayout.getChildCount();
        if (index < 0 || index > childCount) {
            index = childCount;
        }
        mFooterLayout.getViewSet().addViews(index, view);
        return this;
    }

    public GYRecyclerAdapter<Model, VH> addFooterView(View header, int index) {
        return addFooterView(header, index, mFooterLayout == null ? LinearLayout.VERTICAL : mFooterLayout.getOrientation());
    }

    public GYRecyclerAdapter<Model, VH> addFooterView(View header) {
        return addFooterView(header, -1);
    }

    public GYRecyclerAdapter<Model, VH> removeFooterView(View header) {
        if (!hasFooterLayout()) {
            return this;
        }
        mFooterLayout.removeView(header);
        if (mFooterLayout.getChildCount() == 0) {
            notifyItemRangeRemoved(getHeaderLayoutCount() + mModelList.size(), 1);
        }
        return this;
    }

    public GYRecyclerAdapter<Model, VH> removeFooterAllViews() {
        if (!hasFooterLayout()) {
            return this;
        }
        mFooterLayout.removeAllViews();
        notifyItemRangeRemoved(getHeaderLayoutCount() + mModelList.size(), 1);
        return this;
    }

    private boolean hasFooterLayout() {
        return mFooterLayout != null && mFooterLayout.getChildCount() > 0;
    }

    public int getFooterLayoutCount() {
        return hasFooterLayout() ? 1 : 0;
    }

    private OnItemClickListener mOnItemClickListener;

    public GYRecyclerAdapter<Model, VH> setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
        return this;
    }

    private OnItemChildClickListener mOnItemChildClickListener;

    public GYRecyclerAdapter<Model, VH> setOnItemChildClickListener(OnItemChildClickListener onItemChildClickListener) {
        mOnItemChildClickListener = onItemChildClickListener;
        return this;
    }

    private OnItemLongClickListener mOnItemLongClickListener;

    public GYRecyclerAdapter<Model, VH> setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
        mOnItemLongClickListener = onItemLongClickListener;
        return this;
    }

    public GYRecyclerAdapter<Model, VH> addChildClickViewIds(List<Integer> viewIdList) {
        childClickViewIds.addAll(viewIdList);
        return this;
    }

    public GYRecyclerAdapter<Model, VH> addChildClickViewIds(@IdRes Integer... viewIds) {
        return addChildClickViewIds(Arrays.asList(viewIds));
    }

    public LinkedHashSet<Integer> getChildClickViewIds() {
        return childClickViewIds;
    }

    @Override
    public int getItemViewType(int position) {
        if (hasHeaderLayout() && position == 0) {
            return ItemViewType.HEADER;
        } else if (hasFooterLayout() && position == (getHeaderLayoutCount() + mModelList.size())) {
            return ItemViewType.FOOTER;
        } else {
            return ItemViewType.ITEM;
        }
    }
}
